import Utils from "./Utils.js";

export default class Algorithm {
    constructor() {
        if (Algorithm.instance) {
            return Algorithm.instance;
        }
        Algorithm.instance = this;

        this.utils = new Utils();

        this.threshold = 0.000001;
        this.espgBase = -5000000;
        this.espgWidth = 10000000;
        this.cadWidth = 100000;
        this.valkyrie = this.utils.getLocalStorage('valkyrie');
    }

    unit(x, y) {
        this.valkyrie = {
            unit: 0.0,
            baseX: x - this.cadWidth / 2,
            baseY: y - this.cadWidth / 2,
            left: x - this.cadWidth / 2,
            right: x + this.cadWidth / 2,
            bottom: y - this.cadWidth / 2,
            top: y + this.cadWidth / 2
        };
        this.valkyrie.unit = this.espgWidth / this.cadWidth;
        this.utils.setLocalStorage('valkyrie', this.valkyrie);
    }

    pointInBox(x, y, left, right, bottom, top) {
        return x >= left && x <= right && y >= bottom && y <= top;
    }

    boxInBox(left, right, bottom, top) {
        return left >= this.valkyrie.left && right <= this.valkyrie.right
            && bottom >= this.valkyrie.bottom && top <= this.valkyrie.top;
    }

    normal(v) {
        return v * this.valkyrie.unit;
    }

    denormal(v) {
        return v / this.valkyrie.unit;
    }

    normalX(x) {
        return this.espgBase + (x - this.valkyrie.baseX) * this.valkyrie.unit;
    }

    normalY(y) {
        return this.espgBase + (y - this.valkyrie.baseY) * this.valkyrie.unit;
    }

    denormalX(x) {
        return this.valkyrie.baseX + (x - this.espgBase) / this.valkyrie.unit;
    }

    denormalY(y) {
        return this.valkyrie.baseY + (y - this.espgBase) / this.valkyrie.unit;
    }

        setConfig(config) {
        this.utils.setLocalStorage("config", config);
    }

    getConfig() {
        return this.utils.getLocalStorage("config");
    }

    // 圆弧
    arc(x, y, r, startAngle = 0, endAngle = 360) {
        let start_angle = startAngle, end_angle = endAngle;
        if (startAngle > endAngle) {
            start_angle = startAngle - 360;
        }

        const xys = [];
        for (let i = start_angle; i < end_angle; i++) {
            const _x = x + r * Math.cos((i * Math.PI) / 180);
            const _y = y + r * Math.sin((i * Math.PI) / 180);
            xys.push([_x, _y]);
        }
        if (endAngle === 360) {
            xys.push(xys[0]);
        }
        return xys;
    }

    // 椭圆
    ellipse(cx, cy, ux, uy, vx, vy, s = 0.0, e = 2 * Math.PI) {
        const xys = [];
        for (let i = s; i < e + 0.1; i = i + 0.1) {
            const _x = cx + Math.cos(i) * ux + Math.sin(i) * vx;
            const _y = cy + Math.cos(i) * uy + Math.sin(i) * vy;
            xys.push([_x, _y]);
        }
        xys.push(xys[0]);
        return xys;
    }

    // 斜率
    k(x1, y1, x2, y2) {
        return Math.atan((y2 - y1) / (x2 - x1));
    }

    // 计算点线段的垂线点: True-在线段上,False-不在线段上
    pointAtLine(p, ls, le) {
        const dx = ls[0] - le[0], dy = ls[1] - le[1], fp = [0, 0];
        if (Math.abs(dx) < this.threshold && Math.abs(dy) < this.threshold) {
            return { foot: p, flag: true }
        }

        let u = (p[0] - ls[0]) * (ls[0] - le[0]) + (p[1] - ls[1]) * (ls[1] - le[1]);
        u = u / ((dx * dx) + (dy * dy));
        fp[0] = ls[0] + u * dx;
        fp[1] = ls[1] + u * dy;

        const maxX =  ls[0] > le[0] ? ls[0] : le[0];
        const minX =  ls[0] < le[0] ? ls[0] : le[0];
        const maxY =  ls[1] > le[1] ? ls[1] : le[1];
        const minY =  ls[1] < le[1] ? ls[1] : le[1];

        let flag = false;
        if ((fp[0] <= maxX && fp[0] >= minX) && (fp[1] <= maxY && fp[1] >= minY)) {
            flag = true;
        }
        return { foot: fp, flag: flag }
    }

    // 判断点在直线的左右
    pointIsLineLR(p, start, end){
        const x = (start[0] - end[0]) / (start[1] - end[1]) * (p[1] - end[1]) + end[0];
        return x > p[0];
    }

    // 计算两点距离
    distance(x1,  y1,  x2,  y2){
        const dx = Math.floor(Math.abs(x1 - x2));
        const dy = Math.floor(Math.abs(y1 - y2));
        return Math.sqrt(dx * dx + dy * dy);
    }

    // 判断两点是否为同一个点
    isSame(x1, y1, x2, y2) {
        const dx = Math.abs(Math.floor(x1 - x2));
        const dy = Math.abs(Math.floor(y1 - y2));
        return dx <= this.threshold && dy <= this.threshold;
    }

    box(points) {
        const box = {
            left: points[0][0],
            right:points[0][0],
            bottom: points[0][1],
            top: points[0][1]
        };
        points.forEach((p) => {
            box.left =  p[0] < box.left ? p[0] : box.left;
            box.right = p[0] > box.right ? p[0] : box.right
            box.bottom = p[1] < box.bottom ? p[1] : box.bottom
            box.top = p[1] > box.top ? p[1] : box.top
        })

        return box
    }

    twist(x, y, angle) {
        const a = Math.PI * angle / 180;
        const _x = x * Math.cos(a) - y * Math.sin(a);
        const _y = x * Math.sin(a) + y * Math.cos(a);
        return [_x, _y];
    }
}